package game.pong.views.components
{
	import away3d.core.base.Object3D;
	import away3d.primitives.Sphere;
	
	import flash.events.Event;
	import flash.events.TimerEvent;
	
	import game.pong.business.Gamespeed;
	import game.pong.events.ScoreEvent;
	import game.pong.events.SoundEvent;

	public class Ball3D extends Sphere
	{
		/** Timer to handle the refresh method */	
		private var ticker : Gamespeed = new Gamespeed();
		
		/** The gameArea of the ball (which will give the ball's boundaries) */
		public var gameArea : Object3D;
		
		/** Velocity in the X direction */
		public var vX : Number = 0;
		
		/** Velocity in the Y direction */
		public var vY : Number = 0;
		
		/** Bouncers the ball collides with (type :  Bouncer) */
		public var bouncers : Array;
		
		/** Constructor	 */	
		public function Ball3D(init : Object = null)
		{
			super(init);
			ticker.addEventListener(TimerEvent.TIMER, refresh);
		}
		
		/**
		 * Update the movement of the ball
		 */
		public function refresh(event : Event) : void
		{
			// Update based on velocity
			x = ((x + gameArea.maxX) + vX) - gameArea.maxX;
			y = ((y + gameArea.maxY) + vY) - gameArea.maxY;
			
			// Check if we've gone off the left side (Computer wins)
			if (x <= gameArea.minX - 100)
				updateScore(false);

			// Check if we've gone off the right side (player wins)
			if (x >= gameArea.maxX + 100)
				updateScore(true);
			
			// Check if we've gone off the top or the bottom of the game area
			if (y >= gameArea.maxY || y <= gameArea.minY)
			{
				// Reverse Y direction and bounce
				vY = -vY;
				y += vY;
				dispatchEvent(new SoundEvent(SoundEvent.BOUNCE_SIMPLE));
			}
			
			// Check if we hit any of the bouncers. If we did, have it bounce us.
			for (var it : String in bouncers)
			{
				var bouncer : AbstractPaddle3D = bouncers[it];
				// Check if we hit the current bouncer
				if (hitTestObject(bouncer))
				{
					// Bounce off the current bouncer and stop checking
					bouncer.bounce(this);
					break;
				}
			}
		}
		
		/**
		 * Sphere doesn't extend Sprite so there's no hitTestObject method built in 
		 * @param bouncer
		 * @return 
		 * 
		 */		
		private function hitTestObject(bouncer : Object3D) : Boolean
		{
			var bouncerminX : Number = bouncer.x + bouncer.minX;
			var bouncermaxX : Number = bouncer.x + bouncer.maxX;
			var bouncerminY : Number = bouncer.y + bouncer.minY;
			var bouncermaxY : Number = bouncer.y + bouncer.maxY;

			if ((x <= bouncermaxX && x >= bouncerminX) && (y <= bouncermaxY && y >= bouncerminY))
					return true;
				
			return false;
		}
		
		/**
		 * Update the score by dispatching a ScoreEvent
		 * @param updateUser
		 */		
		private function updateScore(updateUser : Boolean) : void
		{
			reset();
			var scoreEvent : ScoreEvent = new ScoreEvent(ScoreEvent.UPDATE);
			scoreEvent.updateUser = updateUser;
			dispatchEvent(scoreEvent);
			dispatchEvent(new SoundEvent(SoundEvent.LOST_BALL));
		}
		
		/**
		 * Reset method
		 * @param event
		 */	
		public function reset(event : Event = null) : void
		{
			ticker.resetSpeed();
			x = 0;
			y = 0;
			// Serve the ball by giving it a random initial velocity
			vX = (Math.random() % 2 == 0 ? 1 : -1) * 10;
			vY = Math.random() % 5;
			ticker.start();
		}
		
		/**
		 * Start method 
		 * 
		 */	
		public function start() : void
		{
			reset();
			ticker.start();
		}
		
		/**
		 * Stop method 
		 * 
		 */	
		public function stop() : void
		{
			reset();
			ticker.stop();
		} 
		
	}
}